/**
 * Mostra o uso das distribuições boost::random que encapsulei como:
 * - GaussianDistribution.h
 * - UniformIntDistribution.h
 * - UniformRealDistribution.h
 * 
 * Crio vetores (std::vector<double>) e os ordeno (std::sort), para simular uma priority queue
 * (std::priority_queue<double>). Também uso um pouquinho uma priority queue.
 * 
 * Todos as amostras geradas são plotadas com o matplotpp. Cada gráfico utiliza uma layer,
 * que pode ser acessada passando o mouse no canto superior esquerdo da tela do matplotpp.
 */

#include <unistd.h>
#include <stdlib.h>
#include <iostream>
#include "matplotpp.h"
#include <vector>
#include <queue>
#include "GaussianDistribution.h"
#include "UniformRealDistribution.h"
#include "UniformIntDistribution.h"

using namespace std;

class MP : public MatPlot {
private:
    vector<double> x;
    vector<double> y;
    vector<double> y_ordered_by_priority_queue;
    vector<double> y_ordered_by_sort;
    vector<double> z_gaussian;
    vector<double> z_gaussian_ordered_by_sort;
    vector<double> w_uniformint;
    vector<double> w_uniformint_ordered_by_sort;

public:

    MP() {
        x = linspace(1, 5000, 5000);
        priority_queue<double, std::vector<double>, std::greater<double> > pq;

        for (int i = 0; i < 5000; i++) y.push_back(UniformRealDistribution::rand(0, 10));
        for (int i = 0; i < 5000; i++) pq.push(y[i]); //ordena

        while (!pq.empty()) {
            y_ordered_by_priority_queue.push_back(pq.top());
            pq.pop();
        }

        y_ordered_by_sort = y;
        sort(y_ordered_by_sort.begin(), y_ordered_by_sort.end());

        for (int i = 0; i < 5000; i++) z_gaussian.push_back(GaussianDistribution::rand(0, 1));
        z_gaussian_ordered_by_sort = z_gaussian;
        sort(z_gaussian_ordered_by_sort.begin(), z_gaussian_ordered_by_sort.end());

        for (int i = 0; i < 5000; i++) w_uniformint.push_back(UniformIntDistribution::rand(-5, 8));
        w_uniformint_ordered_by_sort = w_uniformint;
        sort(w_uniformint_ordered_by_sort.begin(), w_uniformint_ordered_by_sort.end());
    }

    void DISPLAY() {
        layer("layer 1", 1);
        title("Distribuicao Uniforme Real");
        plot(x, y);
        layer("layer 2", 0);
        title("Distribuicao Uniforme Real ordenada com priority_queue");
        plot(x, y_ordered_by_priority_queue);
        layer("layer 3", 0);
        title("Distribuicao Uniforme Real ordenada com std::sort");
        plot(x, y_ordered_by_sort);
        layer("layer 4", 0);
        title("Distribuicao Gaussiana");
        plot(x, z_gaussian);
        layer("layer 4", 0);
        title("Distribuicao Gaussiana ordenada com std::sort");
        plot(x, z_gaussian_ordered_by_sort);
        layer("layer 5", 0);
        title("Distribuicao Uniforme Inteira");
        plot(x, w_uniformint);
        layer("layer 6", 0);
        title("Distribuicao Uniforme Inteira ordenada com std::sort");
        plot(x, w_uniformint_ordered_by_sort);
    }
} mp;

void display() {
    mp.display();
}

void reshape(int w, int h) {
    mp.reshape(w, h);
}

void idle(void) {
    glutPostRedisplay();
    usleep(10000);
}

void motion(int x, int y) {
    mp.motion(x, y);
}

void mouse(int button, int state, int x, int y) {
    mp.mouse(button, state, x, y);
}

void passive(int x, int y) {
    mp.passivemotion(x, y);
}

void keyboard(unsigned char key, int x, int y) {
    mp.keyboard(key, x, y);
}

int main(int argc, char* argv[]) {
    glutInit(&argc, argv);
    glutCreateWindow(100, 100, 400, 300);
    glutDisplayFunc(display);
    glutSetWindowTitle("Teste do matplotpp");
    glutReshapeFunc(reshape);
    glutIdleFunc(idle);
    glutMotionFunc(motion);
    glutMouseFunc(mouse);
    glutPassiveMotionFunc(passive);
    glutKeyboardFunc(keyboard);
    glutMainLoop();
    return 0;
}
